并发编程是指在一台处理器上“同时”处理多个任务。
多进程就是用来实现并发编程
多进程可以理解为多个异步的代码
进程就是为了实现代码的异步执行
如果开启了多进程,就是多个进程几乎同时开始执行
进程的使用场景:
- 如果两个任务需要数据隔离,且想实现异步,那么就是用多进程
- 高计算类型的程序(只是做算数用的程序)一般都会多进程
开多进程,进程数超过3个以上就使用进程池来处理
multiprocess 模块 -> 综合的管理进程的包
在window下做开发所有创建进程的程序都要放在 if __name__ == '__main__' 下执行,因为当创建一个子进程会把代码在执行一遍,就是为了避免死循环
当多个进程去修改同一个数据的时候,就会引发数据安全或顺序混乱问题。
1. 获取进程的 pid
import os
print(os.getpid()) # 248 获取当前进程的 pid
print(os.getppid()) # 5604 获取当前父进程的 pid
2. Process 类 -> 用于创建进程
- Process(target=函数名, args=函数接收的参数) -> args 必须接收一个元组
from multiprocessing import Process
def fn(d1, d2):
print('----子进程----')
print(d1, d2)
if __name__ == '__main__':
p = Process(target=fn, args=('数据一', '数据二')) # 创建一个进程执行一个函数 -> 此时 if __name__ == '__main__': 下的代码就相当于主进程,而 fn函数 就相当于子进程
p.start() # 启动进程,执行进程所绑定的函数
print('-------主进程-------') # 当进程启动后 p.start() 下方的代码不会等待进程所绑定的函数执行完再开始执行,而是直接往下执行,因为此时进程所绑定的函数已经变成了异步代码了
# 执行结果:
# -------主进程-------
# ----子进程----
# 数据一 数据二

- .join() -> 主进程的代码会在 .json() 这里进行阻塞,等待子进程(进程所绑定的函数)执行完后,才会往下执行 -> 当使用了.join(),程序就会变成同步执行了
from multiprocessing import Process
def fn(d1, d2):
print('----子进程----')
print(d1, d2)
if __name__ == '__main__':
p = Process(target=fn, args=('数据一', '数据二'))
p.start()
p.join() # 阻塞 -> 等待子进程(进程所绑定的函数)执行完后,才会往下执行
print('-------主进程-------')
# 执行结果:
# ----子进程----
# 数据一 数据二
# -------主进程-------
- 开启多个子进程
# 开启多个子进程一
from multiprocessing import Process
def fn(d1, d2):
print(d1, d2)
if __name__ == '__main__':
p1 = Process(target=fn, args=('数据一', '数据二')) # 创建第一个进程
p2 = Process(target=fn, args=('data1', 'data2')) # 创建第二个进程
p1.start() # 执行第一个进程
p2.start() # 执行第二个进程
print('-------主进程-------')
# 执行结果:
# -------主进程-------
# 数据一 数据二
# data1 data2
# 开启多个子进程二
from multiprocessing import Process
def fn(data):
print(data)
if __name__ == '__main__':
for i in range(10):
p = Process(target=fn, args=(i,))
p.start()
print('-------主进程-------')
# 执行结果:
# 0
# 1
# 2
# 3
# 4
# -------主进程-------
# 5
# 6
# 7
# 8
# 9
- 当所有子进程执行完后,主进程才开始执行
# 正确示范一
from multiprocessing import Process
def fn(d1, d2):
print(d1, d2)
if __name__ == '__main__':
p1 = Process(target=fn, args=('数据一', '数据二'))
p2 = Process(target=fn, args=('data1', 'data2'))
p1.start()
p2.start()
p1.join()
p2.join()
print('-------主进程-------')
# 执行结果:
# 数据一 数据二
# data1 data2
# -------主进程-------
# 正确示范二
from multiprocessing import Process
def fn(data):
print(data)
if __name__ == '__main__':
p_list = []
for i in range(10):
p = Process(target=fn, args=(i,))
p.start()
p_list.append(p) # 将所有子进程放进列表中
for i in p_list: # 当所有子进程都执行完了才会继续往执行
i.join()
print('-------主进程-------')
# 执行结果:
# 1
# 0
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
# -------主进程-------
# 错误示范一
from multiprocessing import Process
def fn(data):
print(data)
if __name__ == '__main__':
p_list = []
for i in range(10):
p = Process(target=fn, args=(i,))
p.start()
p.join() # 如果join放在循环里就表示当绑定的函数执行完才循环一次
print('-------主进程-------')
# 错误示范二
from multiprocessing import Process
def fn(data):
print(data)
if __name__ == '__main__':
p_list = []
for i in range(10):
p = Process(target=fn, args=(i,))
p.start()
p.join() # 如果 join放在外面就表示阻塞子进程最后一个
print('-------主进程-------')
- 开启多个子进程使用 .join() 的注意事项
from multiprocessing import Process
def fn(d1, d2):
print('----子进程----')
print(d1, d2)
if __name__ == '__main__':
p1 = Process(target=fn, args=('数据一', '数据二'))
p2 = Process(target=fn, args=('data1', 'data2'))
p1.start()
p2.start()
p1.join() # 此时等待p1的子进程(进程所绑定的函数)执行完后,才会往下执行,而不是等待所有子进程结束
print('-------主进程-------')
# 执行结果:
# ----子进程----
# 数据一 数据二
# -------主进程-------
# ----子进程----
# data1 data2
2.进程函数调用外部变量或函数的注意事项
- 如果要调用的变量和函数在 if __name__ == '__main__': 里面必须用传参的形式调用不然就会报错,因为进程函数无法直接调用 if __name__ == '__main__': 里面的方法和函数,如果是直接执行该函数是可以的,但是如果是被进程执行就不行
from multiprocessing import Process
def fun(if_data):
print(data) # 直接调用进程函数外部的并且不在 if __name__ == '__main__': 里面的变量,函数是可以直接调用函数外部的变量或方法(因为作用域链)
print(if_data) # 使用传参的形式调用 if __name__ == '__main__': 里面的变量
data = '外部参数'
if __name__ == '__main__':
if_data = 'if_main里面的参数'
p = Process(target=fun, args=(if_data,))
p.start()
3. 创建进程的方法二 -> 通过继承方式
import os
from multiprocessing import Process
class MyProcess(Process): # 通过继承 Process 类,从而创建一个进程
def __init__(self, d1, d2):
super().__init__()
self.d1 = d1
self.d2 = d2
def run(self): # run 方法就相当于进程所绑定的函数
print('子进程: ', os.getpid(), self.d1, self.d2)
self.other_fn()
def other_fn(self):
print('其他方法')
if __name__ == '__main__':
p = MyProcess('数据1', '数据2') # 创建一个进程
p.start() # 当进程启动的时候就会调用类中的 run 方法
print('-----主进程-----')
# 执行结果:
# -----主进程-----
# 子进程: 3116 数据1 数据2
# 其他方法
4. 多进程的应用
- 创建多个进程实现TCP协议多人聊天 -> 因为每个进程之间是独立的所以可以实现TCP协议的多人通讯
# server.py
import socket
from multiprocessing import Process
def talk(conn):
conn.send(b'world')
msg = conn.recv(1024).decode('utf-8')
print(msg)
if __name__ == '__main__':
sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen()
while True:
conn, addr = sk.accept() # 等待客户端链接
p = Process(target=talk, args=(conn,))
p.start()
conn.close()
sk.close()
# client1.py
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 8080))
print(sk.recv(1024).decode('utf-8'))
sk.send(input('>>>').encode('utf-8'))
sk.close()
# client2.py
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 8080))
print(sk.recv(1024).decode('utf-8'))
sk.send(input('>>>').encode('utf-8'))
sk.close()
5. 守护进程
- 守护进程会随着主进程的代码执行结束而结束,不会等待其他子进程
2FCL(]4T1.png)
# 报时器例子: 每个1秒就会报一次时
# 开启了守护进程 -> cal_time 会随着主进程的代码执行结束而结束
import time
from multiprocessing import Process
def cal_time():
while True:
time.sleep(1)
print('过去了1秒')
if __name__ == '__main__':
p = Process(target=cal_time)
p.daemon = True # 开启守护进程,一定要设置在 start 之前
p.start()
for i in range(100):
time.sleep(0.1)
print('*' * i)
# 报时器例子: 每个1秒就会报一次时
# 没有开启守护进程 -> cal_time子进程会一直执行
import time
from multiprocessing import Process
def cal_time():
while True:
time.sleep(1)
print('过去了1秒')
if __name__ == '__main__':
p = Process(target=cal_time)
p.start()
for i in range(100):
time.sleep(0.1)
print('*' * i)
# 上面图片的代码
import time
from multiprocessing import Process
# 守护进程
def cal_time():
while True:
time.sleep(1)
print('过去了1秒')
# 其他子进程
def fun():
print('--' * 10)
time.sleep(15)
print('--' * 10)
if __name__ == '__main__':
# 守护进程
p = Process(target=cal_time)
p.daemon = True # 开启守护进程
p.start()
# 其他子进程
p2 = Process(target=fun)
p2.start()
# 主进程代码
for i in range(100):
time.sleep(0.1)
print('*' * i)
p2.join() # 如果守护进程想等待其他进程结束后再结束,可以使用join
6.进程的其他方法
- .is_alive() -> 判断进程是否存活 -> 返回值: True: 进程没有结束 False 进程以结束
import time
from multiprocessing import Process
def fun():
print('---子进程---')
if __name__ == '__main__':
p = Process(target=fun)
p.start()
print(p.is_alive()) # True
time.sleep(5)
print(p.is_alive()) # False
- .terminate() -> 手动结束进程 -> 如果调用了 terminate 进程是不会立刻结束的,terminate只是向系统发送了一条结束该进程的指令,terminate就相当于异步执行
import time
from multiprocessing import Process
def fun():
print('---子进程---')
if __name__ == '__main__':
p = Process(target=fun)
p.start()
print(p.is_alive()) # True
p.terminate()
print(p.is_alive()) # True -> 进程是不会立刻结束的,terminate只是向系统发送了一条结束该进程的指令,terminate就相当于异步执行
time.sleep(0.1)
print(p.is_alive()) # False
← logging 日志模块 os 模块 →